# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-08-04 23:35
# File     : analysis_chain.py
# Project  : codebuddy_craft
# Desc     : 代码分析链
# backend/core/chains/analysis_chain.py
from typing import Dict, List, Optional, Any
import asyncio
import ast
import re

from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field

from backend.utils.config import get_settings


class CodeIssue(BaseModel):
    """代码问题模型"""
    file_path: str = Field(description="文件路径")
    line: int = Field(description="行号")
    column: Optional[int] = Field(default=None, description="列号")
    type: str = Field(description="问题类型")
    severity: str = Field(description="严重程度", default="medium")
    message: str = Field(description="问题描述")
    suggestion: str = Field(description="修复建议")


class AnalysisResult(BaseModel):
    """分析结果模型"""
    issues: List[CodeIssue] = Field(default=[], description="发现的问题")
    solution: Optional[str] = Field(default=None, description="解决方案代码")
    summary: str = Field(description="分析摘要")
    score: float = Field(description="代码质量评分", ge=0, le=10)


class CodeAnalysisChain:
    """代码分析链"""

    def __init__(self):
        self.settings = get_settings()
        # 使用正确的大写属性名
        api_key = self.settings.OPENAI_API_KEY or "sk-dummy-api-key-for-testing"
        self.llm = ChatOpenAI(
            model=self.settings.OPENAI_MODEL,
            temperature=0.1,
            api_key=api_key
        )

    async def analyze_code(
            self,
            code: str,
            file_path: str = "unknown.py",
            analysis_type: str = "comprehensive"
    ) -> AnalysisResult:
        """分析代码

        Args:
            code: 要分析的代码
            file_path: 文件路径
            analysis_type: 分析类型 (syntax, security, performance, comprehensive)
        """
        try:
            # 根据分析类型选择不同的分析策略
            if analysis_type == "syntax":
                return await self._analyze_syntax(code, file_path)
            elif analysis_type == "security":
                return await self._analyze_security(code, file_path)
            elif analysis_type == "performance":
                return await self._analyze_performance(code, file_path)
            else:
                return await self._analyze_comprehensive(code, file_path)

        except Exception as e:
            return AnalysisResult(
                issues=[],
                summary=f"代码分析失败: {str(e)}",
                score=0.0
            )

    async def _analyze_syntax(self, code: str, file_path: str) -> AnalysisResult:
        """语法分析"""
        issues = []

        try:
            # 对于Python代码，使用AST进行语法检查
            if file_path.endswith('.py'):
                try:
                    ast.parse(code)
                except SyntaxError as e:
                    issues.append(CodeIssue(
                        file_path=file_path,
                        line=e.lineno or 1,
                        column=e.offset,
                        type="语法错误",
                        severity="high",
                        message=str(e),
                        suggestion="请检查语法错误并修正"
                    ))

            # 使用LLM进行更深入的语法分析
            syntax_prompt = ChatPromptTemplate.from_template("""
            请分析以下代码的语法问题：

            文件: {file_path}
            代码:
            ```
            {code}
            ```

            请检查：
            1. 语法错误
            2. 缩进问题
            3. 括号匹配
            4. 变量命名规范
            5. 导入语句问题

            对每个问题，请提供：
            - 问题位置（行号）
            - 问题描述
            - 修复建议

            如果没有发现问题，请说明"未发现语法问题"。
            """)

            chain = syntax_prompt | self.llm
            response = await chain.ainvoke({
                "code": code,
                "file_path": file_path
            })

            # 解析LLM响应
            llm_issues = self._parse_issues_from_response(response.content, file_path)
            issues.extend(llm_issues)

            return AnalysisResult(
                issues=issues,
                summary=f"语法分析完成，发现 {len(issues)} 个问题",
                score=max(0, 10 - len(issues) * 2)
            )

        except Exception as e:
            return AnalysisResult(
                issues=issues,
                summary=f"语法分析失败: {str(e)}",
                score=0.0
            )

    async def _analyze_security(self, code: str, file_path: str) -> AnalysisResult:
        """安全性分析"""
        issues = []

        try:
            # 基于规则的安全检查
            security_patterns = {
                r'sql.*=.*\+.*': "SQL注入风险：使用字符串拼接构造SQL查询",
                r'eval\s*\(': "代码注入风险：使用eval函数",
                r'exec\s*\(': "代码注入风险：使用exec函数",
                r'os\.system\s*\(': "命令注入风险：使用os.system",
                r'subprocess\.(run|call|Popen).*shell=True': "命令注入风险：shell=True",
                r'pickle\.loads?\s*\(': "反序列化风险：使用pickle",
                r'input\s*$.*$': "输入验证：需要验证用户输入",
                r'open\s*\(.*[\'\"]/': "路径遍历风险：使用绝对路径",
                r'hashlib\.(md5|sha1)\s*\(': "弱哈希算法：建议使用SHA-256或更强算法"
            }

            lines = code.split('\n')
            for i, line in enumerate(lines, 1):
                for pattern, message in security_patterns.items():
                    if re.search(pattern, line, re.IGNORECASE):
                        issues.append(CodeIssue(
                            file_path=file_path,
                            line=i,
                            type="安全风险",
                            severity="high",
                            message=message,
                            suggestion="请使用安全的替代方案"
                        ))

            # 使用LLM进行深度安全分析
            security_prompt = ChatPromptTemplate.from_template("""
                            作为安全专家，请分析以下代码的安全风险：

                            文件: {file_path}
                            代码:
                            ```
                            {code}
                            ```

                            请重点检查：
                            1. SQL注入风险
                            2. XSS漏洞
                            3. CSRF攻击
                            4. 输入验证问题
                            5. 权限控制缺陷
                            6. 敏感信息泄露
                            7. 加密算法使用

                            对每个安全问题，请提供：
                            - 风险等级（高/中/低）
                            - 具体位置
                            - 风险描述
                            - 修复建议
                            """)

            chain = security_prompt | self.llm
            response = await chain.ainvoke({
                "code": code,
                "file_path": file_path
            })

            # 解析安全问题
            security_issues = self._parse_security_issues(response.content, file_path)
            issues.extend(security_issues)

            return AnalysisResult(
                issues=issues,
                summary=f"安全分析完成，发现 {len(issues)} 个安全风险",
                score=max(0, 10 - len([i for i in issues if i.severity == "high"]) * 3 -
                          len([i for i in issues if i.severity == "medium"]) * 1)
            )

        except Exception as e:
            return AnalysisResult(
                issues=issues,
                summary=f"安全分析失败: {str(e)}",
                score=0.0
            )

        async def _analyze_performance(self, code: str, file_path: str) -> AnalysisResult:
            """性能分析"""
            issues = []

            try:
                # 基于规则的性能检查
                performance_patterns = {
                    r'for.*in.*range\(len\(': "性能问题：建议使用enumerate代替range(len())",
                    r'\.append\(.*\)\s*in.*for': "性能问题：考虑使用列表推导式",
                    r'time\.sleep\(': "阻塞调用：可能影响性能",
                    r'\.+\*': "字符串拼接：大量拼接时考虑使用join",
                    r'global\s+\w+': "全局变量：可能影响性能和维护性"
                }

                lines = code.split('\n')
                for i, line in enumerate(lines, 1):
                    for pattern, message in performance_patterns.items():
                        if re.search(pattern, line, re.IGNORECASE):
                            issues.append(CodeIssue(
                                file_path=file_path,
                                line=i,
                                type="性能问题",
                                severity="medium",
                                message=message,
                                suggestion="请优化此处代码以提升性能"
                            ))

                # 使用LLM进行性能分析
                performance_prompt = ChatPromptTemplate.from_template("""
                            作为性能优化专家，请分析以下代码的性能问题：

                            文件: {file_path}
                            代码:
                            ```
                            {code}
                            ```

                            请检查：
                            1. 时间复杂度问题
                            2. 空间复杂度问题
                            3. 循环优化机会
                            4. 数据结构选择
                            5. 算法效率
                            6. 内存使用
                            7. I/O操作优化

                            对每个性能问题，请提供：
                            - 问题严重程度
                            - 具体位置
                            - 性能影响描述
                            - 优化建议和代码示例
                            """)

                chain = performance_prompt | self.llm
                response = await chain.ainvoke({
                    "code": code,
                    "file_path": file_path
                })

                # 解析性能问题
                perf_issues = self._parse_performance_issues(response.content, file_path)
                issues.extend(perf_issues)

                return AnalysisResult(
                    issues=issues,
                    summary=f"性能分析完成，发现 {len(issues)} 个性能问题",
                    score=max(0, 10 - len(issues) * 1.5)
                )

            except Exception as e:
                return AnalysisResult(
                    issues=issues,
                    summary=f"性能分析失败: {str(e)}",
                    score=0.0
                )

        async def _analyze_comprehensive(self, code: str, file_path: str) -> AnalysisResult:
            """综合分析"""
            try:
                # 并行执行所有类型的分析
                syntax_result, security_result, performance_result = await asyncio.gather(
                    self._analyze_syntax(code, file_path),
                    self._analyze_security(code, file_path),
                    self._analyze_performance(code, file_path)
                )

                # 合并所有问题
                all_issues = []
                all_issues.extend(syntax_result.issues)
                all_issues.extend(security_result.issues)
                all_issues.extend(performance_result.issues)

                # 计算综合评分
                total_score = (syntax_result.score + security_result.score + performance_result.score) / 3

                # 生成解决方案
                solution = await self._generate_solution(code, all_issues)

                return AnalysisResult(
                    issues=all_issues,
                    solution=solution,
                    summary=f"综合分析完成：语法问题 {len(syntax_result.issues)} 个，"
                            f"安全风险 {len(security_result.issues)} 个，"
                            f"性能问题 {len(performance_result.issues)} 个",
                    score=total_score
                )

            except Exception as e:
                return AnalysisResult(
                    issues=[],
                    summary=f"综合分析失败: {str(e)}",
                    score=0.0
                )

        def _parse_issues_from_response(self, response: str, file_path: str) -> List[CodeIssue]:
            """从LLM响应中解析问题"""
            issues = []

            # 简单的解析逻辑，实际应用中可以更复杂
            lines = response.split('\n')
            current_issue = {}

            for line in lines:
                line = line.strip()
                if '行' in line and '：' in line:
                    # 提取行号
                    import re
                    line_match = re.search(r'第?(\d+)行', line)
                    if line_match:
                        current_issue['line'] = int(line_match.group(1))
                        current_issue['message'] = line.split('：', 1)[1] if '：' in line else line
                elif line.startswith('建议') or line.startswith('修复'):
                    current_issue['suggestion'] = line

                    # 创建问题对象
                    if 'line' in current_issue and 'message' in current_issue:
                        issues.append(CodeIssue(
                            file_path=file_path,
                            line=current_issue['line'],
                            type="代码问题",
                            severity="medium",
                            message=current_issue['message'],
                            suggestion=current_issue.get('suggestion', '请修复此问题')
                        ))
                    current_issue = {}

            return issues

        def _parse_security_issues(self, response: str, file_path: str) -> List[CodeIssue]:
            """解析安全问题"""
            issues = []

            # 查找安全风险关键词
            security_keywords = ['SQL注入', 'XSS', 'CSRF', '注入', '泄露', '加密']
            lines = response.split('\n')

            for i, line in enumerate(lines):
                if any(keyword in line for keyword in security_keywords):
                    # 尝试提取行号
                    import re
                    line_match = re.search(r'第?(\d+)行', line)
                    line_num = int(line_match.group(1)) if line_match else 1

                    issues.append(CodeIssue(
                        file_path=file_path,
                        line=line_num,
                        type="安全风险",
                        severity="high",
                        message=line.strip(),
                        suggestion="请使用安全的替代方案"
                    ))

            return issues

        def _parse_performance_issues(self, response: str, file_path: str) -> List[CodeIssue]:
            """解析性能问题"""
            issues = []

            # 查找性能问题关键词
            perf_keywords = ['性能', '复杂度', '优化', '效率', '循环', '内存']
            lines = response.split('\n')

            for line in lines:
                if any(keyword in line for keyword in perf_keywords):
                    # 尝试提取行号
                    import re
                    line_match = re.search(r'第?(\d+)行', line)
                    line_num = int(line_match.group(1)) if line_match else 1

                    issues.append(CodeIssue(
                        file_path=file_path,
                        line=line_num,
                        type="性能问题",
                        severity="medium",
                        message=line.strip(),
                        suggestion="请优化此处代码以提升性能"
                    ))

            return issues

        async def _generate_solution(self, code: str, issues: List[CodeIssue]) -> Optional[str]:
            """生成解决方案代码"""
            if not issues:
                return None

            try:
                solution_prompt = ChatPromptTemplate.from_template("""
                            请基于以下代码分析结果，生成修复后的代码：

                            原始代码:
                            ```
                            {code}
                            ```

                            发现的问题:
                            {issues_summary}

                            请提供修复后的完整代码，确保：
                            1. 修复所有语法错误
                            2. 解决安全风险
                            3. 优化性能问题
                            4. 保持原有功能不变
                            5. 添加必要的注释
                            """)

                # 生成问题摘要
                issues_summary = "\n".join([
                    f"- 第{issue.line}行: {issue.message}"
                    for issue in issues[:10]  # 限制显示前10个问题
                ])

                chain = solution_prompt | self.llm
                response = await chain.ainvoke({
                    "code": code,
                    "issues_summary": issues_summary
                })

                # 提取代码块
                import re
                code_pattern = r'```[\w]*\n(.*?)\n```'
                matches = re.findall(code_pattern, response.content, re.DOTALL)

                return matches[0].strip() if matches else None

            except Exception:
                return None

# 创建全局实例
code_analysis_chain = CodeAnalysisChain()

